package com.citi.gts.galto.modules.validation;

import com.citi.gts.galto.constant.value.LatamFieldImpl;
import com.citi.gts.galto.core.tools.exception.NonExistenceException;
import com.citi.gts.galto.core.tools.exception.ReferenceException;
import com.citi.gts.galto.core.tools.reference.Field;
import com.citi.gts.galto.modules.validation.vo.SampleInstruction;
import com.citi.gts.galto.tool.Referenceable;

import javax.persistence.Column;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class FieldReference implements Referenceable<String, Field> {


    @Override
    public Field find(String key) throws ReferenceException {

        java.lang.reflect.Field instructionField = null;

        try {

            instructionField = SampleInstruction.class.getDeclaredField(key);

        } catch (NoSuchFieldException e) {
            throw new NonExistenceException("Field \"" + key + "\" is not present in Instruction", e);

        }

        if (instructionField.isAnnotationPresent(Column.class)) {
            return buildField(instructionField);
        }

        throw new ReferenceException("Field \"" + key + "\" is not mapped to a column within table");
    }

    @Override
    public Collection<Field> getAll() throws ReferenceException {

        java.lang.reflect.Field[] instructionFields = SampleInstruction.class.getDeclaredFields();

        List<Field> fieldList = new ArrayList<Field>(instructionFields.length);

        for (java.lang.reflect.Field instructionField : instructionFields) {

            if (instructionField.isAnnotationPresent(Column.class)) {
                fieldList.add(buildField(instructionField));
            }
        }

        return fieldList;
    }

    private static Field buildField(java.lang.reflect.Field instructionField) {

        Column columnAnnotation = instructionField.getAnnotation(Column.class);

        LatamFieldImpl field = new LatamFieldImpl();
        field.setAlphabeticCode(instructionField.getName());
        field.setColumnName(columnAnnotation.name());
        field.setType(instructionField.getType());
        field.setLength(columnAnnotation.length());
        field.setNullable(columnAnnotation.nullable());

        return field;
    }

}
